﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;

namespace SalePartial.Utility
{
    public class MailRecvUtility
    {
        public static string[] receiveMail()
        {
            return Receive("pop.gmail.com", 995, "jianglanshui@gmail.com", "jiang123", false);
        }

        /// <summary>
        /// POP3サーバーからメールをすべて受信する
        /// </summary>
        /// <param name="hostName">POP3サーバー名</param>
        /// <param name="portNumber">POP3サーバーのポート番号</param>
        /// <param name="userId">ユーザーID</param>
        /// <param name="passWord">パスワード</param>
        /// <param name="deleteMails">メールを削除するか</param>
        /// <returns>取得したメールの配列</returns>
        public static string[] Receive(string hostName, int portNumber,
            string userId, string passWord, bool deleteMails)
        {
            string[] mails;
            string msg = "";
            NetworkStream stream = null;

            //TcpClientの作成
            TcpClient client = new TcpClient();
            //タイムアウトの設定
            client.ReceiveTimeout = 10000;
            client.SendTimeout = 10000;

            try
            {
                //サーバーに接続
                client.Connect(hostName, portNumber);
                //ストリームの取得
                stream = client.GetStream();
                //受信
                //msg = ReceiveData(stream);

                //USERの送信
                SendData(stream, "USER " + userId + "\r\n");
                //受信
                //msg = ReceiveData(stream);

                //PASSの送信
                SendData(stream, "PASS " + passWord + "\r\n");
                //受信
                //msg = ReceiveData(stream);

                //STATの送信
                SendData(stream, "STAT\r\n");
                //受信
                msg = ReceiveData(stream);
                //メール数の取得
                int mailsCount = int.Parse(msg.Split(' ')[1]);
                mails = new string[mailsCount];

                //すべてのメールの内容を受信
                for (int i = 1; i <= mailsCount; i++)
                {
                    //RETRの送信（メール本文を受信）
                    SendData(stream, "RETR " + i.ToString() + "\r\n");
                    //受信
                    msg = ReceiveData(stream, true);
                    mails[i - 1] = msg.Substring(msg.IndexOf("\r\n") + 2);

                    //メールを削除するか
                    if (deleteMails)
                    {
                        //DELEの送信（メールに削除マークを付ける）
                        SendData(stream, "DELE " + i.ToString() + "\r\n");
                        //受信
                        msg = ReceiveData(stream);
                    }
                }

                //QUITの送信
                SendData(stream, "QUIT\r\n");
                //受信
                msg = ReceiveData(stream);
            }
            catch
            {
                throw;
            }
            finally
            {
                //切断
                if (stream != null)
                {
                    stream.Close();
                }
                client.Close();
            }

            return mails;
        }

        //データを受信する
        private static string ReceiveData(NetworkStream stream,
            bool multiLines, int bufferSize, Encoding enc)
        {
            byte[] data = new byte[bufferSize];
            int len;
            string msg = "";
            System.IO.MemoryStream ms = new System.IO.MemoryStream();

            //すべて受信する
            //(無限ループに陥る恐れあり)
            do
            {
                //受信
                len = stream.Read(data, 0, data.Length);
                ms.Write(data, 0, len);
                //文字列に変換する
                msg = enc.GetString(ms.ToArray());
            }
            while (stream.DataAvailable ||
                ((!multiLines || msg.StartsWith("-ERR")) &&
                !msg.EndsWith("\r\n")) ||
                (multiLines && !msg.EndsWith("\r\n.\r\n")));

            ms.Close();

            //"-ERR"を受け取った時は例外をスロー
            if (msg.StartsWith("-ERR"))
            {
                throw new ApplicationException("Received Error");
            }

            //表示
            Console.Write("S: " + msg);

            return msg;
        }
        private static string ReceiveData(NetworkStream stream,
            bool multiLines, int bufferSize)
        {
            return ReceiveData(stream, multiLines, bufferSize,
                Encoding.GetEncoding(50220));
        }
        private static string ReceiveData(NetworkStream stream,
            bool multiLines)
        {
            return ReceiveData(stream, multiLines, 256);
        }
        private static string ReceiveData(NetworkStream stream)
        {
            return ReceiveData(stream, false);
        }

        //データを送信する
        private static void SendData(NetworkStream stream,
            string msg, Encoding enc)
        {
            //byte型配列に変換
            byte[] data = enc.GetBytes(msg);
            //送信
            stream.Write(data, 0, data.Length);

            //表示
            Console.Write("C: " + msg);
        }
        private static void SendData(NetworkStream stream,
            string msg)
        {
            SendData(stream, msg, Encoding.ASCII);
        }
    }
}
